// @ts-expect-error the enquirer types are incomplete https://github.com/enquirer/enquirer/pull/307
import { AutoComplete } from 'enquirer';

import { logger } from '../../cli';
import { type Database } from '../index';
import type { Environment } from './types';
import { ensureSingle, generateIdIsh, getDbChoice, matchIdIsh } from './util';

const loadBaseEnvironmentForWorkspace = (db: Database, workspaceId: string): Environment => {
  logger.trace('Load base environment for the workspace `%s` from data store', workspaceId);
  const items = db.Environment.filter(environment => environment.parentId === workspaceId);
  logger.trace('Found %d environment(s).', items.length);
  return ensureSingle(items, 'base environment');
};

export const loadEnvironment = (
  db: Database,
  workspaceId: string,
  identifier?: string,
): Environment | null | undefined => {
  if (!db.Environment.length) {
    logger.trace('No environments found in given data store, not loading any environment');
    return null;
  }

  // If no identifier, return base environment
  if (!identifier) {
    logger.trace('No sub environments found, using base environment');
    return loadBaseEnvironmentForWorkspace(db, workspaceId);
  }

  logger.trace('Load sub environment with identifier `%s` from data store', identifier);
  return db.Environment.find(env => matchIdIsh(env, identifier) || env.name === identifier);
};

export const promptEnvironment = async (
  db: Database,
  ci: boolean,
  workspaceId: string,
): Promise<Environment | null | undefined> => {
  if (!db.Environment.length) {
    logger.warn('No environments found');
    return null;
  }

  // Get the sub environments
  const baseWorkspaceEnv = loadBaseEnvironmentForWorkspace(db, workspaceId);
  const subEnvironments = db.Environment.filter(subEnv => subEnv.parentId === baseWorkspaceEnv._id);

  if (!subEnvironments.length) {
    logger.trace('No sub environments found, using base environment');
    return baseWorkspaceEnv;
  }

  // We know at this point that an environment was not specified as an argument, so if there is
  // only one, and we're in CI mode, use it.
  if (ci && subEnvironments.length === 1) {
    logger.trace(`Only one environment found in CI mode, using it (${subEnvironments[0].name})`);
    return subEnvironments[0];
  }

  if (ci) {
    logger.error(
      `Multiple environments found in CI mode (${subEnvironments.map(s => s.name).join(', ')}). ` +
        'Select one using --env <identifier>.',
    );
    return null;
  }

  const prompt = new AutoComplete({
    name: 'environment',
    message: 'Select an environment',
    choices: subEnvironments.map(subEnv => getDbChoice(generateIdIsh(subEnv, 14), subEnv.name)),
  });
  logger.trace('Prompt for environment');
  const [idIsh] = (await prompt.run()).split(' - ').reverse();
  return loadEnvironment(db, workspaceId, idIsh);
};
